package com.vcc.boss.controller;


import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaCheckSafe;
import cn.idev.excel.ExcelWriter;
import cn.idev.excel.write.metadata.WriteSheet;
import com.mybatisflex.core.paginate.Page;
import com.vcc.core.annotations.RepeatSubmit;
import com.vcc.core.annotations.RestPack;
import com.vcc.core.derive.admin.DeriveCardOrder;
import com.vcc.core.exception.NotFoundException;
import com.vcc.core.exception.ProgramException;
import com.vcc.core.util.ExportUtil;
import com.vcc.core.util.RegexUtil;
import com.vcc.data.entity.*;
import com.vcc.service.boss.request.cardOrder.BossCardOrderUpdateRequest;
import com.vcc.service.client.vo.cardOrder.CardOrderVo;
import com.vcc.service.service.BossUserService;
import com.vcc.service.service.CardOrderService;
import com.vcc.service.service.UserCardService;
import com.vcc.service.service.UserService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.log4j.Log4j2;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.math.RoundingMode;
import java.util.List;

@Log4j2
@RestController
@RequestMapping("/cardOrder")
public class CardOrderController {

    @Resource
    private CardOrderService cardOrderService;
    @Resource
    private UserService userService;
    @Resource
    private BossUserService bossUserService;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private UserCardService userCardService;


    @GetMapping("/paging")
    @SaCheckLogin
    @SaCheckPermission(value = "card:order:list:view")
    @RestPack
    public Page<CardOrderVo> paging(
            Integer pageNumber,
            Integer pageSize,
            String orderId,
            Long cardTypeId,
            String type,
            String status,
            Long targetUserId,
            String cardNumber,
            Long userCardId,
            String startDate,
            String endDate,
            Long dealerId
    ) {
        Page<CardOrder> page = cardOrderService.paging(
                Page.of(
                        pageNumber == null ? 1 : pageNumber,
                        pageSize == null ? 20 : pageSize
                ),
                targetUserId,
                cardTypeId,
                orderId,
                "",
                type,
                status,
                cardNumber,
                startDate,
                endDate,
                userCardId,
                dealerId
        );
        if (page == null) {
            return Page.of(pageNumber == null ? 1 : pageNumber, pageSize == null ? 20 : pageSize);
        }
        return page.map(CardOrderVo::new);

    }


    @GetMapping("/derive")
    @SaCheckLogin
    @SaCheckPermission(value = "card:order:list:derive")
    @RestPack
    public void derive(
            String orderId,
            Long cardTypeId,
            String type,
            String status,
            Long targetUserId,
            String cardNumber,
            Long userCardId,
            String startDate,
            String endDate,
            Long dealerId,
            HttpServletResponse response
    ) {
        if (RegexUtil.checkStringIsNull(startDate)) {
            throw new ProgramException("请选择开始时间");
        }
        if (RegexUtil.checkStringIsNull(endDate)) {
            throw new ProgramException("请选择结束时间");
        }
        Long pages = 1L;
        Page<CardOrder> paging;
        String fileName = System.currentTimeMillis() + "卡操作订单.xlsx";
        ExcelWriter excelWriter;
        try {
            ExportUtil.setExcelResponseHeaders(response, fileName);
            excelWriter = ExportUtil.createExcelWriter(response.getOutputStream(), DeriveCardOrder.class);
        } catch (Exception e) {
            log.error("导出卡操作订单数据失败", e);
            throw new ProgramException("导出卡操作订单数据失败");
        }
        WriteSheet writeSheet = ExportUtil.createWriteSheet("卡操作订单", DeriveCardOrder.class);
        try {
            do {
                paging = cardOrderService.paging(
                        Page.of(
                                pages++,
                                500
                        ),
                        targetUserId,
                        cardTypeId,
                        orderId,
                        "",
                        type,
                        status,
                        cardNumber,
                        startDate,
                        endDate,
                        userCardId,
                        dealerId
                );
                List<DeriveCardOrder> list = paging.getRecords().stream().map(it -> DeriveCardOrder.builder()
                        .id(it.getId())
                        .userId(it.getUserId())
                        .account(it.getAccount())
                        .operatorAccount(it.getOperatorAccount())
                        .cardNumber(it.getCardNumber())
                        .cardNumberId(it.getCardNumberId())
                        .cardTypeId(it.getCardTypeId())
                        .orderNo(it.getOrderNo())
                        .orderStatus(it.getOrderStatus())
                        .orderAmount(it.getOrderAmount() == null ? null : it.getOrderAmount().setScale(2, RoundingMode.HALF_UP))
                        .orderCurrency(it.getOrderCurrency())
                        .orderType(it.getOrderType())
                        .requestTime(it.getRequestTime())
                        .completeTime(it.getCompleteTime())
                        .orderRemark(it.getOrderRemark())
                        .orderSource(it.getOrderSource())
                        .dealerAccount(it.getDealerAccount())
                        .build()).toList();
                ExportUtil.writeData(excelWriter, writeSheet, list);
                list = null;
            } while (!(pages).equals(paging.getTotalPage() + 1));
        } catch (Exception e) {
            log.error("导出失败", e);
            throw new ProgramException("导出失败");
        }
        ExportUtil.closeExcelWriter(excelWriter);

    }


    @RestPack
    @SaCheckPermission(value = "card:order:list:edit")
    @PostMapping("updateOrder")
    @SaCheckSafe("CARD_ORDER_UPDATE")
    @SaCheckLogin
    @RepeatSubmit
    public void updateOrder(@RequestBody @Validated BossCardOrderUpdateRequest bossCardOrderUpdateRequest) {
        CardOrder cardOrder = cardOrderService.getByIdOpt(bossCardOrderUpdateRequest.getId())
                .orElseThrow(() -> new NotFoundException("订单不存在"));
        if (!cardOrder.getOrderStatus().equals("PENDING")) {
            throw new ProgramException("只有待处理的订单才能修改");
        }
        RLock lock = redissonClient.getLock("CARD_ORDER_UPDATE_LOCK_" + cardOrder.getId());
        try {
            boolean tryLock = lock.tryLock();
            if (!tryLock) {
                throw new ProgramException("系统繁忙，请稍后再试");
            }

            switch (cardOrder.getOrderType()) {
                case "OPEN" -> {
                    UserCard userCard = null;
                    if (bossCardOrderUpdateRequest.getStatus().equals("SUCCESS")) {
                        userCard = userCardService.getByOrderId(cardOrder.getOrderNo());
                        if (userCard == null) {
                            throw new ProgramException("用户卡信息不存在，请稍后再试");
                        }
                    }
                    boolean result = cardOrderService.openCardComplete(
                            cardOrder.getOrderNo(),
                            bossCardOrderUpdateRequest.getStatus().equals("SUCCESS") ? userCard.getCardNumber() : null,
                            bossCardOrderUpdateRequest.getStatus().equals("SUCCESS") ? userCard.getId() : null,
                            bossCardOrderUpdateRequest.getStatus()
                    );
                    if (!result) {
                        throw new ProgramException("操作失败，请稍后再试");
                    }
                }
                case "RECHARGE" -> {
                    boolean result = cardOrderService.rechargeCardComplete(
                            cardOrder.getOrderNo(),
                            cardOrder.getCardNumber(),
                            cardOrder.getCardNumberId(),
                            bossCardOrderUpdateRequest.getStatus()
                    );
                    if (!result) {
                        throw new ProgramException("操作失败，请稍后再试");
                    }
                }
                case "WITHDRAW" -> {
                    boolean result = cardOrderService.withdrawCardComplete(
                            cardOrder.getOrderNo(),
                            cardOrder.getCardNumber(),
                            cardOrder.getCardNumberId(),
                            bossCardOrderUpdateRequest.getStatus()
                    );
                    if (!result) {
                        throw new ProgramException("操作失败，请稍后再试");
                    }
                }
                case "BLOCK" -> {
                    boolean result = cardOrderService.blockCardComplete(
                            cardOrder.getOrderNo(),
                            bossCardOrderUpdateRequest.getStatus()
                    );
                    if (!result) {
                        throw new ProgramException("操作失败，请稍后再试");
                    }
                }
                case "UNBLOCK" -> {
                    boolean result = cardOrderService.unblockCardComplete(
                            cardOrder.getOrderNo(),
                            bossCardOrderUpdateRequest.getStatus()
                    );
                    if (!result) {
                        throw new ProgramException("操作失败，请稍后再试");
                    }
                }
            }
        } catch (Exception e) {
            log.error("更新订单状态失败", e);
            if (e instanceof NotFoundException || e instanceof ProgramException) {
                throw e;
            }
            throw new ProgramException("系统繁忙，请稍后再试");
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

    }
}
